home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pico / pico.c < prev    next >
C/C++ Source or Header  |  1996-05-06  |  34KB  |  1,499 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: pico.c,v 4.95 1996/05/07 00:52:40 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Main Pine Composer routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1996 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  *
  30.  * WEEMACS/PICO NOTES:
  31.  *
  32.  * 01 Nov 89 - MicroEmacs 3.6 vastly pared down and becomes a function call 
  33.  *            weemacs() and plugged into the Pine mailer.  Lots of unused
  34.  *           MicroEmacs code laying around.
  35.  *
  36.  * 17 Jan 90 - weemacs() became weemacs() the composer.  Header editing
  37.  *           functions added.
  38.  *
  39.  * 09 Sep 91 - weemacs() renamed pico() for the PIne COmposer.
  40.  *
  41.  */
  42.  
  43.  
  44. /*
  45.  * This program is in public domain; written by Dave G. Conroy.
  46.  * This file contains the main driving routine, and some keyboard processing
  47.  * code, for the MicroEMACS screen editor.
  48.  *
  49.  * REVISION HISTORY:
  50.  *
  51.  * 1.0  Steve Wilhite, 30-Nov-85
  52.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  53.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  54.  *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  55.  *      Steve Wilhite, 1-Dec-85
  56.  *      - massive cleanup on code in display.c and search.c
  57.  *
  58.  * 2.0  George Jones, 12-Dec-85
  59.  *      - Ported to Amiga.
  60.  *
  61.  * 3.0  Daniel Lawrence, 29-Dec-85
  62.  *    16-apr-86
  63.  *    - updated documentation and froze development for 3.6 net release
  64.  */
  65.  
  66. #include        <stdio.h>
  67. #include    <setjmp.h>
  68. #include    <time.h>
  69.  
  70. /* make global definitions not external */
  71. #define    maindef
  72.  
  73. #include    "osdep.h"    /* operating system dependent includes */
  74. #include    "pico.h"    /* PIne COmposer definitions */
  75. #include        "estruct.h"    /* global structures and defines */
  76. #include    "efunc.h"    /* function declarations and name table    */
  77. #include    "edef.h"    /* global definitions */
  78. #include    "ebind.h"    /* default key bindings */
  79.  
  80.  
  81. #ifdef    ANSI
  82.     int  func_init(void);
  83.     void breplace(void *);
  84.     int  any_header_changes(void);
  85. #ifdef    _WINDOWS
  86.     int    composer_file_drop(int, int, char *);
  87. #endif
  88. #else
  89.     int  func_init();
  90.     void breplace();
  91.     int  any_header_changes();
  92. #endif
  93.  
  94.  
  95. /*
  96.  * function key mappings
  97.  */
  98. static int pfkm[12][2] = {
  99.     { F1,  (CTRL|'G')},
  100.     { F2,  (CTRL|'C')},
  101.     { F3,  (CTRL|'X')},
  102.     { F4,  (CTRL|'J')},
  103.     { F5,  (CTRL|'R')},
  104.     { F6,  (CTRL|'W')},
  105.     { F7,  (CTRL|'Y')},
  106.     { F8,  (CTRL|'V')},
  107.     { F9,  (CTRL|'K')},
  108.     { F10, (CTRL|'U')},
  109.     { F11, (CTRL|'O')},
  110. #ifdef    SPELLER
  111.     { F12, (CTRL|'T')}
  112. #else
  113.     { F12, (CTRL|'D')}
  114. #endif
  115. };
  116.  
  117.  
  118. /*
  119.  * flag for the various functions in pico() to set when ready
  120.  * for pico() to return...
  121.  */
  122. int      pico_all_done = 0;
  123. jmp_buf  finstate;
  124. char    *pico_anchor = NULL;
  125. extern struct headerentry *headents;
  126.  
  127. /*
  128.  * pico - the main routine for Pine's composer.
  129.  *
  130.  */
  131. pico(pm)
  132. PICO *pm;
  133. {
  134.     register int    c;
  135.     register int    f;
  136.     register int    n;
  137.     char     bname[NBUFN];        /* buffer name of file to read */
  138.     extern   struct on_display ods;
  139.     int      checkpointcnt = 0;
  140.     char     chkptfile[NLINE];
  141.  
  142.     Pmaster       = pm;
  143.     gmode      = MDWRAP;
  144.     gmode        |= pm->pine_flags;    /* high 4 bits rsv'd for pine */
  145.  
  146.     alt_speller   = pm->alt_spell;
  147.     pico_all_done = 0;
  148.     km_popped     = 0;
  149.  
  150.     if(!vtinit())            /* Init Displays.      */
  151.       return(COMP_CANCEL);
  152.  
  153.     strcpy(bname, "main");        /* default buffer name */
  154.     edinit(bname);            /* Buffers, windows.   */
  155.  
  156.     if(InitMailHeader(pm))        /* init mail header structure */
  157.       gmode &= ~(P_BODY | P_HEADEND);    /* flip off special header stuff */
  158.  
  159.     /* setup to process commands */
  160.     lastflag = 0;            /* Fake last flags.     */
  161.     curbp->b_mode |= gmode;        /* and set default modes*/
  162.  
  163.     pico_anchor = (char *)malloc((strlen(Pmaster->pine_anchor) + 1)
  164.                  * sizeof(char));
  165.     if(pico_anchor)
  166.       strcpy(pico_anchor, Pmaster->pine_anchor);
  167.  
  168.     bindtokey(DEL, (gmode & P_DELRUBS) ? forwdel : backdel);
  169.  
  170.     if(pm->msgtext)
  171.       breplace(pm->msgtext);
  172.  
  173. #ifdef    _WINDOWS
  174.     mswin_allowpaste(MSWIN_PASTE_FULL);
  175.     mswin_setscrollcallback (pico_scroll_callback);
  176. #endif
  177.  
  178.     pico_all_done = setjmp(finstate);    /* jump out of HUP handler ? */
  179.  
  180.     if(gmode & MDALTNOW){
  181.     while(!pico_all_done){
  182.         if(((gmode & P_BODY) || !Pmaster->headents)
  183.            && alt_editor(0, 1) < 0)
  184.           break;            /* if problem, drop into pico */
  185.  
  186.         if(Pmaster->headents){
  187.         update();        /* paint screen, n' start editing... */
  188.         HeaderEditor((gmode & (P_HEADEND | P_BODY)) ? 2 : 0, 0);
  189.         gmode |= P_BODY;    /* make sure we enter alt ed next */
  190.         }
  191.         else
  192.           pico_all_done = COMP_EXIT;
  193.     }
  194.     }
  195.     else if(!pico_all_done){
  196.     if(gmode & P_BODY){        /* begin editing the header? */
  197.         ArrangeHeader();        /* line up pointers */
  198.     }
  199.     else{
  200.         update();            /* paint screen, */
  201.         HeaderEditor((gmode & P_HEADEND) ? 2 : 0, 0);
  202.     }
  203.  
  204.     /* prepare for checkpointing */
  205.     chkptfile[0] = '\0';
  206.     chkptinit((*Pmaster->ckptdir)(chkptfile, NLINE), NLINE);
  207.     }
  208.  
  209.     while(1){
  210.     if(pico_all_done){
  211. #ifdef    _WINDOWS
  212.         mswin_allowpaste(MSWIN_PASTE_DISABLE);
  213.         mswin_setscrollcallback (NULL);
  214. #endif
  215.         c = anycb() ? BUF_CHANGED : 0;
  216.         switch(pico_all_done){    /* prepare for/handle final events */
  217.           case COMP_EXIT :        /* already confirmed */
  218.         packheader();
  219.         c |= COMP_EXIT;
  220.         break;
  221.  
  222.           case COMP_CANCEL :    /* also already confirmed */
  223.         packheader();
  224.         c = COMP_CANCEL;
  225.         break;
  226.  
  227.           case COMP_GOTHUP:
  228.         /* 
  229.          * pack up and let caller know that we've received a SIGHUP
  230.          */
  231.         if(ComposerEditing)        /* expand addr if needed */
  232.           call_builder(&headents[ods.cur_e]);
  233.  
  234.         packheader();
  235.         c |= COMP_GOTHUP;
  236.         break;
  237.  
  238.           case COMP_SUSPEND :
  239.           default:            /* safest if internal error */
  240.         packheader();
  241.         c |= COMP_SUSPEND;
  242.         break;
  243.         }
  244.  
  245.         free(pico_anchor);
  246.         vttidy();            /* clean up tty modes */
  247.         zotdisplay();        /* blast display buffers */
  248.         zotedit();
  249.         unlink(chkptfile);
  250.         Pmaster = NULL;        /* blat global */
  251.  
  252.         return(c);
  253.     }
  254.  
  255.     if(km_popped){
  256.         km_popped--;
  257.         if(km_popped == 0) /* cause bottom three lines to be repainted */
  258.           curwp->w_flag |= WFHARD;
  259.     }
  260.  
  261.     if(km_popped){  /* temporarily change to cause menu to be painted */
  262.         term.t_mrow = 2;
  263.         curwp->w_ntrows -= 2;
  264.         curwp->w_flag |= WFMODE;
  265.         movecursor(term.t_nrow-2, 0); /* clear status line, too */
  266.         peeol();
  267.     }
  268.  
  269.     update();            /* Fix up the screen    */
  270.     if(km_popped){
  271.         term.t_mrow = 0;
  272.         curwp->w_ntrows += 2;
  273.     }
  274.  
  275. #ifdef    MOUSE
  276. #ifdef  EX_MOUSE
  277.     /* New mouse function for real mouse text seletion. */
  278.     register_mfunc(mouse_in_pico, 2, 0, term.t_nrow - (term.t_mrow+1),
  279.                term.t_ncol);
  280. #else
  281.     mouse_in_content(K_MOUSE, -1, -1, -1, 0);
  282.     register_mfunc(mouse_in_content, 2, 0, term.t_nrow - (term.t_mrow + 1),
  283.                term.t_ncol);
  284. #endif
  285. #endif
  286. #ifdef    _WINDOWS
  287.     mswin_setdndcallback (composer_file_drop);
  288. #endif
  289.     c = GetKey();    
  290. #ifdef    MOUSE
  291. #ifdef  EX_MOUSE
  292.     clear_mfunc(mouse_in_pico);
  293. #else
  294.     clear_mfunc(mouse_in_content);
  295. #endif
  296. #endif
  297. #ifdef    _WINDOWS
  298.     mswin_cleardndcallback ();
  299. #endif
  300.     if(c == NODATA || time_to_check()){    /* new mail ? */
  301.         if((*Pmaster->newmail)(c == NODATA ? 0 : 2, 1) >= 0){
  302.         if(km_popped){
  303.             term.t_mrow = 2;
  304.             curwp->w_ntrows -= 2;
  305.             curwp->w_flag |= WFHARD;
  306.             km_popped = 0;
  307.         }
  308.  
  309.         clearcursor();
  310.         mlerase();
  311.         (*Pmaster->showmsg)(c);
  312.         mpresf = 1;
  313.         }
  314.  
  315.         clearcursor();
  316.         movecursor(0, 0);
  317.     }
  318.  
  319.     if(km_popped)
  320.       switch(c){
  321.         case NODATA:
  322.         case (CTRL|'L'):
  323.           km_popped++;
  324.           break;
  325.         
  326.         default:
  327.           mlerase();
  328.           break;
  329.       }
  330.  
  331.     if(c == NODATA)        /* no op, getkey timed out */
  332.       continue;
  333.  
  334.     if (mpresf != FALSE) {        /* message stay around only  */
  335.         if (mpresf++ > NMMESSDELAY)    /* so long! */
  336.           mlerase();
  337.     }
  338.  
  339.     f = FALSE;            /* vestigial */
  340.     n = 1;
  341.                     /* Do it.               */
  342.     execute(normalize_cmd(c, pfkm, 2), f, n);
  343.     if(++checkpointcnt >= CHKPTDELAY){
  344.         checkpointcnt = 0;
  345.         writeout(chkptfile);
  346.     }
  347.     }
  348. }
  349.  
  350. /*
  351.  * Initialize all of the buffers and windows. The buffer name is passed down
  352.  * as an argument, because the main routine may have been told to read in a
  353.  * file by default, and we want the buffer name to be right.
  354.  */
  355.  
  356. /*
  357.  * For the pine composer, we don't want to take over the whole screen
  358.  * for editing.  the first some odd lines are to be used for message 
  359.  * header information editing.
  360.  */
  361. edinit(bname)
  362. char    bname[];
  363. {
  364.     register BUFFER *bp;
  365.     register WINDOW *wp;
  366.  
  367.     if(Pmaster)
  368.       func_init();
  369.  
  370.     bp = bfind(bname, TRUE, BFWRAPOPEN);    /* First buffer         */
  371.     wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  372.  
  373.     if (bp==NULL || wp==NULL){
  374.     if(Pmaster)
  375.       return(0);
  376.     else
  377.       exit(1);
  378.     }
  379.  
  380.     curbp  = bp;                            /* Make this current    */
  381.     wheadp = wp;
  382.     curwp  = wp;
  383.     wp->w_wndp  = NULL;                     /* Initialize window    */
  384.     wp->w_bufp  = bp;
  385.     bp->b_nwnd  = 1;                        /* Displayed.           */
  386.     wp->w_linep = bp->b_linep;
  387.     wp->w_dotp  = bp->b_linep;
  388.     wp->w_doto  = 0;
  389.     wp->w_markp = NULL;
  390.     wp->w_marko = 0;
  391.     bp->b_linecnt = -1;
  392.  
  393.     if(Pmaster){
  394.     term.t_mrow = Pmaster->menu_rows;
  395.     wp->w_toprow = ComposerTopLine = COMPOSER_TOP_LINE;
  396.     wp->w_ntrows = term.t_nrow - COMPOSER_TOP_LINE - term.t_mrow;
  397.     fillcol = Pmaster->fillcolumn;
  398.     if(Pmaster->oper_dir)
  399.       strncpy(opertree, Pmaster->oper_dir, NLINE);
  400.     }
  401.     else{
  402.     if(sup_keyhelp)
  403.       term.t_mrow = 0;
  404.     else
  405.       term.t_mrow = 2;
  406.  
  407.         wp->w_toprow = 2;
  408.         wp->w_ntrows = term.t_nrow - 2 - term.t_mrow;
  409.     if(userfillcol > 0)            /* set fill column */
  410.       fillcol = userfillcol;
  411.     else
  412.       fillcol = term.t_ncol - 6;
  413.     }
  414.  
  415.     /*
  416.      * MDSCUR mode implies MDTREE mode with a opertree of home directory,
  417.      * unless opertree has been set differently.
  418.      */
  419.     if(gmode&MDSCUR && !*opertree)
  420.       strncpy(opertree, gethomedir(NULL), NLINE);
  421.  
  422.     if(*opertree){
  423.     fixpath(opertree, NLINE);
  424.     gmode |= MDTREE;
  425.     }
  426.  
  427.     wp->w_force = 0;
  428.     wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  429. }
  430.  
  431.  
  432. /*
  433.  * This is the general command execution routine. It handles the fake binding
  434.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  435.  * and arranges to move it to the "lastflag", so that the next command can
  436.  * look at it. Return the status of command.
  437.  */
  438. execute(c, f, n)
  439. int c, f, n;
  440. {
  441.     register KEYTAB *ktp;
  442.     register int    status;
  443.     register int    i;
  444.  
  445.     ktp = (Pmaster) ? &keytab[0] : &pkeytab[0];
  446.  
  447.     while (ktp->k_fp != NULL) {
  448.     if (ktp->k_code == c) {
  449.  
  450.         if(lastflag&CFFILL){
  451.         curwp->w_flag |= WFMODE;
  452.         if(Pmaster == NULL)
  453.           sgarbk = TRUE;
  454.         }
  455.  
  456.         thisflag = 0;
  457.         status   = (*ktp->k_fp)(f, n);
  458.         if((lastflag & CFFILL) && (thisflag ^ CFFILL))
  459.           fdelete();
  460.  
  461.         lastflag = thisflag;
  462.  
  463.         /*
  464.          * Reset flag saying wrap should open a new line whenever
  465.          * we execute a command (as opposed to just typing in text).
  466.          * However, if that command leaves us in the same line on the
  467.          * screen, then don't reset.
  468.          */
  469.         if(curwp->w_flag & (WFMOVE | WFHARD))
  470.           curbp->b_flag |= BFWRAPOPEN;    /* wrap should open new line */
  471.  
  472.         return (status);
  473.     }
  474.     ++ktp;
  475.     }
  476.  
  477.     if(lastflag & CFFILL)        /* blat unusable fill data */
  478.       fdelete();
  479.  
  480.     if (VALID_KEY(c)) {            /* Self inserting.      */
  481.  
  482.     if (n <= 0) {                   /* Fenceposts.          */
  483.         lastflag = 0;
  484.         return (n<0 ? FALSE : TRUE);
  485.     }
  486.     thisflag = 0;                   /* For the future.      */
  487.  
  488.     /* if we are in overwrite mode, not at eol,
  489.        and next char is not a tab or we are at a tab stop,
  490.        delete a char forword            */
  491.     if (curwp->w_bufp->b_mode & MDOVER &&
  492.         curwp->w_doto < curwp->w_dotp->l_used &&
  493.         (lgetc(curwp->w_dotp, curwp->w_doto).c != '\t' ||
  494.          (curwp->w_doto) % 8 == 7))
  495.       ldelete(1L, FALSE);
  496.  
  497.     /* do the appropriate insertion */
  498.     /* pico never does C mode, this is simple */
  499.     status = linsert(n, c);
  500.  
  501.     /*
  502.      * Check to make sure we didn't go off of the screen
  503.      * with that character.  Take into account tab expansion.
  504.      * If so wrap the line...
  505.      */
  506.     if(curwp->w_bufp->b_mode & MDWRAP){
  507.         register int j;
  508.         register int k;
  509.  
  510.         for(i = j = k = 0; j < llength(curwp->w_dotp); j++, k++)
  511.           if(isspace((unsigned char)lgetc(curwp->w_dotp, j).c)){
  512.           if(lgetc(curwp->w_dotp, j).c == TAB)
  513.             while(k+1 & 0x07)
  514.               k++;
  515.           }
  516.           else if(k >= fillcol){
  517.           wrapword();
  518.           break;
  519.           }
  520.     }
  521.  
  522.     lastflag = thisflag;
  523.     return (status);
  524.     }
  525.     
  526.     if(c&CTRL)
  527.       emlwrite("\007Unknown Command: ^%c", (void *)(c&0xff));
  528.     else
  529.       emlwrite("\007Unknown Command", NULL);
  530.  
  531.     lastflag = 0;                           /* Fake last flags.     */
  532.     return (FALSE);
  533. }
  534.  
  535.  
  536.  
  537. /*
  538.  * Fancy quit command, as implemented by Norm. If the any buffer has
  539.  * changed do a write on that buffer and exit emacs, otherwise simply exit.
  540.  */
  541. quickexit(f, n)
  542. int f, n;
  543. {
  544.     register BUFFER *bp;    /* scanning pointer to buffers */
  545.  
  546.     bp = bheadp;
  547.     while (bp != NULL) {
  548.     if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  549.         && (bp->b_flag&BFTEMP) == 0) {    /* Real.                */
  550.         curbp = bp;        /* make that buffer cur    */
  551.         filesave(f, n);
  552.     }
  553.     bp = bp->b_bufp;            /* on to the next buffer */
  554.     }
  555.     wquit(f, n);                             /* conditionally quit   */
  556. }
  557.  
  558.  
  559.  
  560. /* 
  561.  * abort_composer - ask the question here, then go quit or 
  562.  *                  return FALSE
  563.  */
  564. abort_composer(f, n)
  565. int f, n;
  566. {
  567.     char *result;
  568.  
  569.     result = "";
  570.  
  571.     if(Pmaster->canceltest){
  572.         if(((Pmaster->pine_flags & P_ABOOK && !any_header_changes())
  573.          || (!(Pmaster->pine_flags & P_ABOOK) && !anycb()))
  574.       || (result = (*Pmaster->canceltest)())){
  575.         pico_all_done = COMP_CANCEL;
  576.         emlwrite(result, NULL);
  577.         return(TRUE);
  578.     }
  579.     else{
  580.         emlwrite("Cancel Cancelled", NULL);
  581.         curwp->w_flag |= WFMODE;        /* and modeline so we  */
  582.         sgarbk = TRUE;            /* redraw the keymenu  */
  583.         pclear(term.t_nrow - 1, term.t_nrow + 1);
  584.         return(FALSE);
  585.     }
  586.     }
  587.     else switch(mlyesno(Pmaster->headents
  588.      ? "Cancel message (answering \"Yes\" will abandon your mail message)"
  589.      : (anycb() == FALSE)
  590.          ? "Cancel Edit (and abandon changes)"
  591.          : "Cancel Edit",
  592.      FALSE)){
  593.       case TRUE:
  594.     pico_all_done = COMP_CANCEL;
  595.     return(TRUE);
  596.  
  597.       case ABORT:
  598.     emlwrite("\007Cancel Cancelled", NULL);
  599.     break;
  600.  
  601.       default:
  602.     mlerase();
  603.     }
  604.     return(FALSE);
  605. }
  606.  
  607.  
  608. /*
  609.  * suspend_composer - return to pine with what's been edited so far
  610.  */
  611. suspend_composer(f, n)
  612. int f, n;
  613. {
  614.     if(Pmaster && Pmaster->headents)
  615.       pico_all_done = COMP_SUSPEND;
  616.     else
  617.       (*term.t_beep)();
  618. }
  619.  
  620.  
  621.  
  622. /*
  623.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  624.  * has been changed and not written out. Normally bound to "C-X C-C".
  625.  */
  626. wquit(f, n)
  627. int f, n;
  628. {
  629.     register int    s;
  630.  
  631.     if(Pmaster){
  632.     char *prompt, *result;
  633.  
  634.     /* First, make sure there are no outstanding problems */ 
  635.     if(AttachError()){
  636.         emlwrite("\007Problem with attachments!  Fix errors or delete attachments.", NULL);
  637.         return(FALSE);
  638.     }
  639.  
  640.     /*
  641.      * if we're not in header, show some of it as we verify sending...
  642.      */
  643.     display_for_send();
  644.     if((!(Pmaster->pine_flags & P_ABOOK) || any_header_changes())
  645.        && (result = (*Pmaster->exittest)())){
  646.         if(sgarbf)
  647.           update();
  648.  
  649.         lchange(WFHARD);            /* set update flags... */
  650.         curwp->w_flag |= WFMODE;        /* and modeline so we  */
  651.         sgarbk = TRUE;            /* redraw the keymenu  */
  652.         pclear(term.t_nrow - 2, term.t_nrow + 1);
  653.         emlwrite(result, NULL);
  654.     }
  655.     else{
  656.         pico_all_done = COMP_EXIT;
  657.         return(TRUE);
  658.     }
  659.     }
  660.     else{
  661.         if (f != FALSE                          /* Argument forces it.  */
  662.         || anycb() == FALSE                     /* All buffers clean.   */
  663.                         /* User says it's OK.   */
  664.         || (s=mlyesno("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES)", -1)) == FALSE) {
  665.                 vttidy();
  666.                 exit(0);
  667.         }
  668.  
  669.     if(s == TRUE){
  670.         if(filewrite(0,1) == TRUE)
  671.           wquit(1, 0);
  672.     }
  673.     else if(s == ABORT){
  674.         emlwrite("Exit cancelled", NULL);
  675.         if(term.t_mrow == 0)
  676.           curwp->w_flag |= WFHARD;    /* cause bottom 3 lines to paint */
  677.     }
  678.         return(s);
  679.     }
  680.  
  681.     return(FALSE);
  682. }
  683.  
  684.  
  685. /*
  686.  * Has any editing been done to headers?
  687.  */
  688. any_header_changes()
  689. {
  690.     struct headerentry *he;
  691.  
  692.     for(he = Pmaster->headents; he->name != NULL; he++)
  693.       if(he->dirty)
  694.     break;
  695.     
  696.     return(he->name && he->dirty);
  697. }
  698.  
  699.  
  700. /*
  701.  * Abort.
  702.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  703.  * Sometimes called as a routine, to do general aborting of stuff.
  704.  */
  705. ctrlg(f, n)
  706. int f, n;
  707. {
  708.     emlwrite("Cancelled", NULL);
  709.     return (ABORT);
  710. }
  711.  
  712.  
  713. /* tell the user that this command is illegal while we are in
  714.  *  VIEW (read-only) mode
  715.  */
  716. rdonly()
  717. {
  718.     (*term.t_beep)();
  719.     emlwrite("Key illegal in VIEW mode", NULL);
  720.     return(FALSE);
  721. }
  722.  
  723.  
  724.  
  725. /*
  726.  * reset all globals to their initial values
  727.  */
  728. func_init()
  729. {
  730.     extern int    vtrow;
  731.     extern int    vtcol;
  732.     extern int    lbound;
  733.  
  734.     /*
  735.      * re-initialize global buffer type variables ....
  736.      */
  737.     fillcol = (term.t_ncol > 80) ? 77 : term.t_ncol - 6;
  738.     eolexist = TRUE;
  739.     revexist = FALSE;
  740.     sgarbf = TRUE;
  741.     mpresf = FALSE;
  742.     mline_open = FALSE;
  743.     ComposerEditing = FALSE;
  744.  
  745.     /*
  746.      * re-initialize hardware display variables ....
  747.      */
  748.     vtrow = vtcol = lbound = 0;
  749.     clearcursor();
  750.  
  751.     pat[0] = '\0';
  752. }
  753.  
  754.  
  755. /*
  756.  * pico_help - help function for standalone composer
  757.  */
  758. pico_help(text, title, i)
  759. char *text[], *title;
  760. int i;
  761. {
  762.     register    int numline = 0;
  763.     char        **p;
  764.  
  765.     p = text;
  766.     while(*p++ != NULL) 
  767.       numline++;
  768.     return(wscrollw(COMPOSER_TOP_LINE, term.t_nrow-1, text, numline));
  769. }
  770.  
  771.  
  772.  
  773. /*
  774.  * zotedit() - kills the buffer and frees all lines associated with it!!!
  775.  */
  776. zotedit()
  777. {
  778.     wheadp->w_linep = wheadp->w_dotp = wheadp->w_markp = NULL;
  779.     bheadp->b_linep = bheadp->b_dotp = bheadp->b_markp = NULL;
  780.  
  781.     free((char *) wheadp);            /* clean up window */
  782.     wheadp = NULL;
  783.     curwp  = NULL;
  784.  
  785.     free((char *) bheadp);            /* clean up buffers */
  786.     bheadp = NULL;
  787.     curbp  = NULL;
  788.  
  789.     zotheader();                /* blast header lines */
  790.  
  791.     kdelete();                    /* blast kill buffer */
  792.  
  793. }
  794.  
  795.  
  796. #ifdef    MOUSE
  797. /*
  798.  * Generic mouse handling functions
  799.  */
  800. MENUITEM  menuitems[12];        /* key labels and functions */
  801. MENUITEM *mfunc = NULL;            /* list of regional functions  */
  802. mousehandler_t    mtrack;            /* mouse tracking handler */
  803.  
  804. /* last mouse position */
  805. static  int levent = 0, lrow = 0, lcol = 0, doubleclick, lbutton, lflags;
  806. #ifdef    DOS
  807. static  clock_t lastcalled = 0;
  808. #else
  809. static    time_t    lastcalled = 0;
  810. #endif
  811. static    mousehandler_t lastf;
  812.  
  813.  
  814. /*
  815.  * register_mfunc - register the given function to get called
  816.  *             on mouse events in the given display region
  817.  */
  818. register_mfunc(f, tlr, tlc, brr, brc)
  819. mousehandler_t    f;
  820. int        tlr, tlc, brr, brc;
  821. {
  822.     MENUITEM **mp;
  823.  
  824.     if(!mouseexist())
  825.       return(FALSE);
  826.  
  827.     for(mp = &mfunc; *mp; mp = &(*mp)->next)
  828.       ;
  829.  
  830.     *mp = (MENUITEM *)malloc(sizeof(MENUITEM));
  831.     memset(*mp, 0, sizeof(MENUITEM));
  832.  
  833.     (*mp)->action = f;
  834.     (*mp)->tl.r   = tlr;
  835.     (*mp)->br.r   = brr;
  836.     (*mp)->tl.c   = tlc;
  837.     (*mp)->br.c   = brc;
  838.     (*mp)->lbl.c  = (*mp)->lbl.r = 0;
  839.     (*mp)->label  = "";
  840.     return(TRUE);
  841. }
  842.  
  843.  
  844. /*
  845.  * clear_mfunc - clear any previously set mouse function
  846.  */
  847. void
  848. clear_mfunc(f)
  849. mousehandler_t f;
  850. {
  851.     MENUITEM *mp, *tp;
  852.  
  853.     if(mp = mfunc){
  854.     if(mp->action == f)
  855.       mfunc = mp->next;
  856.     else
  857.       for(tp = mp; tp->next; tp = tp->next)
  858.         if(tp->next->action == f){
  859.         mp = tp->next;
  860.         tp->next = tp->next->next;
  861.         break;
  862.         }
  863.  
  864.     if(mp){
  865.         mp->action = NULL;
  866.         free(mp);
  867.     }
  868.     }
  869. }
  870.  
  871.  
  872.  
  873. #ifdef EX_MOUSE
  874.  
  875. void
  876. clear_mtrack ()
  877. {
  878.     mtrack = NULL;
  879.     mswin_allowmousetrack (FALSE);
  880. }
  881.  
  882.  
  883. void
  884. register_mtrack (f)
  885. mousehandler_t    f;
  886. {
  887.     if (f) {
  888.     mtrack = f;
  889.     mswin_allowmousetrack (TRUE);
  890.     }
  891.     else
  892.     clear_mtrack ();
  893. }
  894.  
  895.  
  896. static void
  897. move_dot_to (row, col)
  898.     int row, col;
  899. {
  900.     LINE *lp;
  901.     int    i;
  902.     
  903.     lp = curwp->w_linep;
  904.     i = row - ((Pmaster) ? ComposerTopLine : 2);
  905.     while(i-- && lp != curbp->b_linep)    /* count from top */
  906.       lp = lforw(lp);
  907.     curgoal = col;
  908.     curwp->w_dotp = lp;            /* to new dot. */
  909.     curwp->w_doto = getgoal(lp);
  910.     curwp->w_flag |= WFMOVE;
  911. }
  912.  
  913.  
  914. /*
  915.  * mouse_in_pico
  916.  *
  917.  * When the mouse goes down in the body we set the mark and start 
  918.  * tracking.
  919.  *
  920.  * As the mouse moves we update the dot and redraw the screen.
  921.  *
  922.  * If the mouse moves above or below the pico body region of the 
  923.  * screen we scroll the text and update the dot position.
  924.  *
  925.  * When the mouse comes up we clean up.  If the mouse did not
  926.  * move, then we clear the mark and turn off the selection.
  927.  *
  928.  * Most of the mouse processing is handled here.  The exception is
  929.  * mouse down in the header.  Can't call HeaderEditor() from here so
  930.  * we send up the K_MOUSE character, which gets dispatched to
  931.  * mousepress(), which _can_ call HeaderEditor().
  932.  */
  933. unsigned long
  934. mouse_in_pico(mevent, row, col, button, flags)
  935.     int         mevent;
  936.     int      row, col, button, flags;
  937. {
  938.     unsigned long    rv = 0;        /* Our return value. */
  939.     int            trow, tcol;    /* translated row and col. */
  940.  
  941.     static int lheader = FALSE;        /* Mouse down was in header. */
  942.  
  943.   
  944.     /*
  945.      * What's up.
  946.      */
  947.     switch (mevent) {
  948.     case M_EVENT_DOWN:
  949.     /* Ignore mouse down if not in pico body region. */
  950.     if (row < 2 || row > term.t_nrow - (term.t_mrow+1)) {
  951.         clear_mtrack ();
  952.         break;
  953.         }
  954.     
  955.     /* Detect double clicks.  Not that we do anything with em, just
  956.      * detect them. */
  957. #ifdef    DOS
  958. #ifdef    CLOCKS_PER_SEC
  959.     doubleclick = (lrow == row && lcol == col
  960.                && clock() < (lastcalled + CLOCKS_PER_SEC/2));
  961. #else
  962. #ifdef    CLK_TCK
  963. doubleclick = (lrow == row && lcol == col
  964.                && clock() < (lastcalled + CLK_TCK/2));
  965. #else
  966.     doubleclick = FALSE;
  967. #endif
  968. #endif
  969.     lastcalled  = clock();
  970. #else
  971.     doubleclick = (lrow == row && lcol == col
  972.                && time(0) < (lastcalled + 2));
  973.     lastcalled  = time(0);
  974. #endif
  975.     lheader        = FALSE;    /* Rember mouse down position. */
  976.     levent        = mevent;
  977.     lrow        = row;
  978.     lcol        = col;
  979.     lbutton     = button;
  980.     lflags      = flags;
  981.     
  982.     /* Mouse down in body? */
  983.     if (row < (Pmaster ? ComposerTopLine : 2)) {
  984.         /* Mouse down in message header -> no tracking, just remember
  985.          * where */
  986.         lheader = TRUE;
  987.         }
  988.     else {
  989.         /* Mouse down in message.
  990.          * If no shift key and an existing mark -> clear the mark.
  991.          * If shift key and no existing mark -> set mark before moving */
  992.         if (!(flags & M_KEY_SHIFT) && curwp->w_markp) 
  993.         setmark (0,1);        /* this clears the mark. */
  994.         else if (flags & M_KEY_SHIFT && !curwp->w_markp)
  995.         setmark (0,1);        /* while this sets the mark. */
  996.         
  997.         /* Reposition dot to mouse down. */
  998.         move_dot_to (row, col);
  999.         
  1000.         /* Set the mark to dot if no existing mark. */
  1001.         if (curwp->w_markp == NULL) 
  1002.         setmark (0,1);
  1003.  
  1004.         /* Track mouse movement. */
  1005.         register_mtrack (mouse_in_pico);
  1006.         update ();
  1007.         lheader = FALSE;        /* Just to be sure. */
  1008.         }
  1009.     break;
  1010.     
  1011.     
  1012.     case M_EVENT_TRACK:
  1013.     /* Mouse tracking. */
  1014.     if (lheader)            /* Ignore mouse movement in header. */
  1015.         break;
  1016.     
  1017.     /* If above or below body, scroll body and adjust the row and col. */
  1018.     if (row < (Pmaster ? ComposerTopLine : 2)) {
  1019.         /* Scroll text down screen and move dot to top left corner. */
  1020.         scrollupline (0,1);
  1021.         trow = (Pmaster) ? ComposerTopLine : 2;
  1022.         tcol = 0;
  1023.         }
  1024.     else if (row > term.t_nrow - (term.t_mrow + 1)) {
  1025.         /* Scroll text up screen and move dot to bottom right corner. */
  1026.         scrolldownline (0,1);
  1027.         trow = term.t_nrow - (term.t_mrow + 1);
  1028.         tcol = term.t_ncol;
  1029.         }
  1030.     else {
  1031.         trow = row;
  1032.         tcol = col;
  1033.         }
  1034.  
  1035.     /* Move dot to target column. */
  1036.     move_dot_to (trow, tcol);
  1037.     
  1038.     /* Update screen. */
  1039.     update ();
  1040.     break;
  1041.  
  1042.     
  1043.     case M_EVENT_UP:
  1044.     if (lheader) {
  1045.         lheader = FALSE;
  1046.         /* Last down in header. */
  1047.         if (row == lrow && col == lcol) {
  1048.         /* Mouse up and down in same place in header.  Means the
  1049.          * user want to edit the header.  Return K_MOUSE which
  1050.          * will cause mousepress to be called, which will
  1051.          * call HeaderEditor.  Can't call HeaderEditor from here
  1052.          * because that would mess up layering. */
  1053.         if (curwp->w_marko)
  1054.             setmark (0,1);
  1055.         rv = ((unsigned long)K_MOUSE << 16) | TRUE;
  1056.         }
  1057.         }
  1058.     else {
  1059.         /* If up at same place, clear mark */
  1060.         if (curwp->w_markp == curwp->w_dotp && 
  1061.             curwp->w_marko == curwp->w_doto) {
  1062.         setmark (0,1);
  1063.         curwp->w_flag |= WFMOVE;
  1064.         }
  1065.         clear_mtrack ();
  1066.         update ();
  1067.         }
  1068.     break;    
  1069.     }
  1070.     
  1071.     return(rv);
  1072. }
  1073. #endif
  1074.  
  1075.  
  1076.  
  1077. /*
  1078.  * mouse_in_content - general mechanism used to pass recognized mouse
  1079.  *              events in predefined region back thru the usual
  1080.  *              keyboard input stream.  The actual return value
  1081.  *              passed back from this function is set dynamically
  1082.  *              via the "down" argument which is read when both the
  1083.  *              "row" and "col" arguments are negative.
  1084.  */
  1085. unsigned long
  1086. mouse_in_content(mevent, row, col, button, flags)
  1087.     int      mevent;
  1088.     int      row, col, button, flags;
  1089. {
  1090.     unsigned long   rv = 0;
  1091.     static unsigned mouse_val = K_MOUSE;
  1092.  
  1093.     if(row == -1 && col == -1){
  1094.     mouse_val = mevent;            /* setting return value */
  1095.     }
  1096.     else {
  1097.     /* A real event. */
  1098.     levent = mevent;
  1099.     switch (mevent) {
  1100.     case M_EVENT_DOWN:
  1101.         /* Mouse down does not mean anything, just keep track of 
  1102.          * where it went down and if this is a double click. */
  1103. #ifdef    DOS
  1104. #ifdef    CLOCKS_PER_SEC
  1105.         doubleclick = (lrow == row && lcol == col
  1106.                && clock() < (lastcalled + CLOCKS_PER_SEC/2));
  1107. #else
  1108. #ifdef    CLK_TCK
  1109.         doubleclick = (lrow == row && lcol == col
  1110.                && clock() < (lastcalled + CLK_TCK/2));
  1111. #else
  1112.         doubleclick = FALSE;
  1113. #endif
  1114. #endif
  1115.         lastcalled    = clock();
  1116. #else
  1117.         doubleclick = (lrow == row && lcol == col
  1118.                && time(0) < (lastcalled + 2));
  1119.         lastcalled  = time(0);
  1120. #endif
  1121.         lrow    = row;
  1122.         lcol    = col;
  1123.         lbutton    = button;
  1124.         lflags    = flags;
  1125.         break;
  1126.  
  1127.     case M_EVENT_UP:
  1128.         /* Mouse up.  If in the same position as it went down
  1129.          * then we return the value set above, which goes into
  1130.          * the character input stream, which gets processed as
  1131.          * a mouse event by some upper layer, which calls to 
  1132.          * mouse_get_last(). */
  1133.         if (lrow == row && lcol == col) {
  1134.         rv = mouse_val;
  1135.         rv = (rv << 16) | TRUE;
  1136.         }
  1137.         break;
  1138.         
  1139.     case M_EVENT_TRACK:
  1140.         break;
  1141.     }
  1142.     }
  1143.  
  1144.     return(rv);
  1145. }
  1146.  
  1147.  
  1148. /*
  1149.  * mouse_get_last - Get last mouse event.
  1150.  *
  1151.  */
  1152. void
  1153. mouse_get_last(f, mp)
  1154.     mousehandler_t *f;
  1155.     MOUSEPRESS *mp;
  1156. {
  1157.     if (f != NULL)
  1158.         *f  = lastf;
  1159.     if (mp != NULL) {
  1160.     mp->mevent    = levent;
  1161.     mp->row        = lrow;
  1162.     mp->col        = lcol;
  1163.     mp->doubleclick = doubleclick;
  1164.     mp->button    = lbutton;
  1165.     mp->flags    = lflags;
  1166.     }
  1167. }
  1168.  
  1169.  
  1170.  
  1171. /*
  1172.  * register_key - register the given keystroke to accept mouse events
  1173.  */
  1174. void
  1175. register_key(i, rval, label, label_printer, row, col, len)
  1176. int       i;
  1177. unsigned  rval;
  1178. char     *label;
  1179. void      (*label_printer)();
  1180. int       row, col, len;
  1181. {
  1182.     if(i > 11)
  1183.       return;
  1184.  
  1185.     menuitems[i].val   = rval;
  1186.     menuitems[i].tl.r  = menuitems[i].br.r = row;
  1187.     menuitems[i].tl.c  = col;
  1188.     menuitems[i].br.c  = col + len;
  1189.     menuitems[i].lbl.r = menuitems[i].tl.r;
  1190.     menuitems[i].lbl.c = menuitems[i].tl.c;
  1191.     menuitems[i].label_hiliter = label_printer;
  1192.     if(menuitems[i].label){
  1193.     free(menuitems[i].label);
  1194.     menuitems[i].label = NULL;
  1195.     }
  1196.  
  1197.     if(label
  1198.        && (menuitems[i].label =(char *)malloc((strlen(label)+1)*sizeof(char))))
  1199.       strcpy(menuitems[i].label, label);
  1200. }
  1201. #endif    /* MOUSE */
  1202.  
  1203.  
  1204. /* 
  1205.  * Below are functions for use outside pico to manipulate text
  1206.  * in a pico's native format (circular linked list of lines).
  1207.  *
  1208.  * The idea is to streamline pico use by making it fairly easy
  1209.  * for outside programs to prepare text intended for pico's use.
  1210.  * The simple char * alternative is messy as it requires two copies
  1211.  * of the same text, and isn't very economic in limited memory
  1212.  * situations (THANKS BELLEVUE-BILLY.).
  1213.  */
  1214. typedef struct picotext {
  1215.     LINE *linep;
  1216.     LINE *dotp;
  1217.     short doto;
  1218.     short crinread;
  1219. } PICOTEXT;
  1220.  
  1221. #define PT(X)    ((PICOTEXT *)(X))
  1222.  
  1223. /*
  1224.  * pico_get - return window struct pointer used as a handle
  1225.  *            to the other pico_xxx routines.
  1226.  */
  1227. void *
  1228. pico_get()
  1229. {
  1230.    PICOTEXT *wp = NULL;
  1231.    LINE     *lp = NULL;
  1232.  
  1233.    if(wp = (PICOTEXT *)malloc(sizeof(PICOTEXT))){
  1234.        wp->crinread = 0;
  1235.        if((lp = lalloc(0)) == NULL){
  1236.        free(wp);
  1237.        return(NULL);
  1238.        }
  1239.  
  1240.        wp->dotp = wp->linep = lp->l_fp = lp->l_bp = lp;
  1241.        wp->doto = 0;
  1242.    }
  1243.    else
  1244.      emlwrite("Can't allocate space for text", NULL);
  1245.  
  1246.    return((void *)wp);
  1247. }
  1248.  
  1249. /*
  1250.  * pico_give - free resources and give up picotext struct
  1251.  */
  1252. void
  1253. pico_give(w)
  1254. void *w;
  1255. {
  1256.     register LINE *lp;
  1257.     register LINE *fp;
  1258.  
  1259.     fp = lforw(PT(w)->linep);
  1260.     while((lp = fp) != PT(w)->linep){
  1261.         fp = lforw(lp);
  1262.     free(lp);
  1263.     }
  1264.     free(PT(w)->linep);
  1265.     free((PICOTEXT *)w);
  1266. }
  1267.  
  1268. /*
  1269.  * pico_readc - return char at current point.  Up to calling routines
  1270.  *              to keep cumulative count of chars.
  1271.  */
  1272. int
  1273. pico_readc(w, c)
  1274. void          *w;
  1275. unsigned char *c;
  1276. {
  1277.     int rv     = 0;
  1278.  
  1279.     if(PT(w)->crinread){
  1280.     *c = '\012';                /* return LF */
  1281.     PT(w)->crinread = 0;
  1282.     rv++;
  1283.     }
  1284.     else if(PT(w)->doto < llength(PT(w)->dotp)){ /* normal char to return */
  1285.         *c = (unsigned char) lgetc(PT(w)->dotp, (PT(w)->doto)++).c;
  1286.     rv++;
  1287.     }
  1288.     else if(PT(w)->dotp != PT(w)->linep){ /* return line break */
  1289.     PT(w)->dotp = lforw(PT(w)->dotp);
  1290.     PT(w)->doto = 0;
  1291. #if    defined(DOS) || defined(OS2)
  1292.     *c = '\015';
  1293.     PT(w)->crinread++;
  1294. #else
  1295.     *c = '\012';                /* return local eol! */
  1296. #endif
  1297.     rv++;
  1298.     }                        /* else no chars to return */
  1299.  
  1300.     return(rv);
  1301. }
  1302.  
  1303.  
  1304. /*
  1305.  * pico_writec - write a char into picotext and advance pointers.
  1306.  *               Up to calling routines to keep track of total chars
  1307.  *               written
  1308.  */
  1309. int
  1310. pico_writec(w, c)
  1311. void *w;
  1312. int   c;
  1313. {
  1314.     int   rv = 0;
  1315.  
  1316.     if(c == '\r')                /* ignore CR's */
  1317.       rv++;                    /* so fake it */
  1318.     else if(c == '\n'){                /* insert newlines on LF */
  1319.     /*
  1320.      * OK, if there are characters on the current line or 
  1321.      * dotp is pointing to the delimiter line, insert a newline
  1322.      * No here's the tricky bit; preserve the implicit EOF newline.
  1323.      */
  1324.     if(lforw(PT(w)->dotp) == PT(w)->linep && PT(w)->dotp != PT(w)->linep){
  1325.         PT(w)->dotp = PT(w)->linep;
  1326.         PT(w)->doto = 0;
  1327.     }
  1328.     else{
  1329.         register LINE *lp;
  1330.  
  1331.         if((lp = lalloc(0)) == NULL){
  1332.         emlwrite("Can't allocate space for more characters",NULL);
  1333.         return(0);
  1334.         }
  1335.  
  1336.         if(PT(w)->dotp == PT(w)->linep){
  1337.         lforw(lp) = PT(w)->linep;
  1338.         lback(lp) = lback(PT(w)->linep);
  1339.         lforw(lback(lp)) = lback(PT(w)->linep) = lp;
  1340.         }
  1341.         else{
  1342.         lforw(lp) = lforw(PT(w)->dotp);
  1343.         lback(lp) = PT(w)->dotp;
  1344.         lback(lforw(lp)) = lforw(PT(w)->dotp) = lp;
  1345.         PT(w)->dotp = lp;
  1346.         PT(w)->doto = 0;
  1347.         }
  1348.     }
  1349.  
  1350.     rv++;
  1351.     }
  1352.     else
  1353.       rv = geninsert(&PT(w)->dotp, &PT(w)->doto, PT(w)->linep, c, 0, 1, NULL);
  1354.  
  1355.     return((rv) ? 1 : 0);            /* return number written */
  1356. }
  1357.  
  1358.  
  1359. /*
  1360.  * pico_puts - just write the given string into the text
  1361.  */
  1362. int
  1363. pico_puts(w, s)
  1364. void *w;
  1365. char *s;
  1366. {
  1367.     while(*s != '\0')
  1368.       pico_writec(w, (int)*s++);
  1369. }
  1370.  
  1371.  
  1372. /*
  1373.  * pico_seek - position dotp and dot at requested location
  1374.  */
  1375. int
  1376. pico_seek(w, offset, orig)
  1377. void *w;
  1378. long  offset;
  1379. int   orig;
  1380. {
  1381.     register LINE *lp;
  1382.  
  1383.     PT(w)->crinread = 0;
  1384.     switch(orig){
  1385.       case 0 :                /* SEEK_SET */
  1386.     PT(w)->dotp = lforw(PT(w)->linep);
  1387.     PT(w)->doto = 0;
  1388.       case 1 :                /* SEEK_CUR */
  1389.     lp = PT(w)->dotp;
  1390.     while(lp != PT(w)->linep){
  1391.         if(offset <= llength(lp)){
  1392.         PT(w)->doto = (int)offset;
  1393.         PT(w)->dotp = lp;
  1394.         break;
  1395.         }
  1396.  
  1397.         offset -= ((long)llength(lp)
  1398. #if defined(DOS) || defined(OS2)
  1399.                + 2L);
  1400. #else
  1401.                + 1L);
  1402. #endif
  1403.         lp = lforw(lp);
  1404.     }
  1405.         break;
  1406.  
  1407.       case 2 :                /* SEEK_END */
  1408.     PT(w)->dotp = lback(PT(w)->linep);
  1409.     PT(w)->doto = llength(PT(w)->dotp);
  1410.     break;
  1411.       default :
  1412.         return(-1);
  1413.     }
  1414.  
  1415.     return(0);
  1416. }
  1417.  
  1418.  
  1419. /*
  1420.  * breplace - replace the current window's text with the given 
  1421.  *            LINEs
  1422.  */
  1423. void
  1424. breplace(w)
  1425. void *w;
  1426. {
  1427.     register LINE *lp;
  1428.     register LINE *fp;
  1429.  
  1430.     fp = lforw(curbp->b_linep);
  1431.     while((lp = fp) != curbp->b_linep){        /* blast old lines */
  1432.         fp = lforw(lp);
  1433.     free(lp);
  1434.     }
  1435.     free(curbp->b_linep);
  1436.  
  1437.     curbp->b_linep   = PT(w)->linep;            /* arrange pointers */
  1438.  
  1439.     curwp->w_linep   = lforw(curbp->b_linep);
  1440.     curwp->w_dotp    = lforw(curbp->b_linep);
  1441.     curwp->w_doto    = 0;
  1442.     curwp->w_markp   = curwp->w_imarkp = NULL;
  1443.     curwp->w_marko   = curwp->w_imarko = 0;
  1444.  
  1445.     curbp->b_dotp    = curwp->w_dotp;
  1446.     curbp->b_doto    = curbp->b_marko  = 0;
  1447.     curbp->b_markp   = NULL;
  1448.     curbp->b_linecnt = -1;
  1449.  
  1450.     curwp->w_flag |= WFHARD;
  1451. }
  1452.  
  1453.  
  1454. #ifdef    _WINDOWS
  1455. /*
  1456.  *
  1457.  */
  1458. int
  1459. composer_file_drop(x, y, filename)
  1460.     int   x, y;
  1461.     char *filename;
  1462. {
  1463.     int attached = 0;
  1464.     if((ComposerTopLine > 2 && x <= ComposerTopLine)
  1465.        || !LikelyASCII(filename)){
  1466.     AppendAttachment(filename, NULL, NULL);
  1467.     attached++;
  1468.     }
  1469.     else{
  1470.     setimark(FALSE, 1);
  1471.     ifile(filename);
  1472.     swapimark(FALSE, 1);
  1473.     }
  1474.  
  1475.     if(ComposerEditing){        /* update display */
  1476.     PaintBody(0);
  1477.     }
  1478.     else{
  1479.     refresh(0, 1);
  1480.     update();
  1481.     }
  1482.  
  1483.     if(attached)
  1484.       emlwrite("Attached dropped file \"%s\"", filename);
  1485.     else
  1486.       emlwrite("Inserted dropped file \"%s\"", filename);
  1487.  
  1488.     if(ComposerEditing){        /* restore cursor */
  1489.     HeaderPaintCursor();
  1490.     }
  1491.     else{
  1492.     curwp->w_flag |= WFHARD;
  1493.     update();
  1494.     }
  1495.  
  1496.     return(1);
  1497. }
  1498. #endif
  1499.